package club.lovety.oauth2.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.oauth2.config.annotation.configurers.ClientDetailsServiceConfigurer;
import org.springframework.security.oauth2.config.annotation.web.configuration.AuthorizationServerConfigurerAdapter;
import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerEndpointsConfigurer;
import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerSecurityConfigurer;
import org.springframework.security.oauth2.provider.ClientDetailsService;
import org.springframework.security.oauth2.provider.OAuth2RequestFactory;
import org.springframework.security.oauth2.provider.client.InMemoryClientDetailsService;
import org.springframework.security.oauth2.provider.client.JdbcClientDetailsService;
import org.springframework.security.oauth2.provider.code.AuthorizationCodeServices;
import org.springframework.security.oauth2.provider.code.InMemoryAuthorizationCodeServices;
import org.springframework.security.oauth2.provider.request.DefaultOAuth2RequestFactory;
import org.springframework.security.oauth2.provider.token.AuthorizationServerTokenServices;
import org.springframework.security.oauth2.provider.token.DefaultTokenServices;
import org.springframework.security.oauth2.provider.token.TokenStore;
import org.springframework.security.oauth2.provider.token.store.InMemoryTokenStore;

import javax.annotation.Resource;
import javax.sql.DataSource;

/**
 * oauth2授权服务,主要是请求,
 * 获取code
 * ${base}/oauth/authorize?response_type=code&client_id=client&redirect_uri=https://baidu.com
 * 获取token
 * ${base}/oauth/token?client_id=client&client_secret=secret&code=bvcA5S&grant_type=authorization_code
 */
@Configuration
public class Oauth2AuthorizationServerConfigurerAdapter extends AuthorizationServerConfigurerAdapter {

    @Resource
    private AuthenticationManager authenticationManager;

    @Resource
    private DataSource dataSource;

    @Resource
    private RedisConnectionFactory connectionFactory;

    @Override
    public void configure(AuthorizationServerSecurityConfigurer security) throws Exception {
        // 配置token获取和验证时的策略
        security.tokenKeyAccess("permitAll()").checkTokenAccess("isAuthenticated()");
    }

    /**
     * @param clients
     * @throws Exception 客户端的服务，验证客户端包括memory和db两种验证
     *                   说白了就是clientId 和 clientSecret在客户端的存储格式
     *                   创建客户端的sql语句 请查看类  JdbcClientDetailsService
     */
    @Override
    public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
        clients.jdbc(dataSource);
    }

    @Override
    public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
        //AuthorizationCodeTokenGranter
        endpoints.authenticationManager(authenticationManager).tokenStore(InMemory()).tokenGranter(getOauthAuthorizationCodeTokenGranter()).authorizationCodeServices(getAuthorizationCodeServices());
    }

    @Bean
    public TokenStore InMemory() {
        return new InMemoryTokenStore();
    }


    @Bean
    public AuthorizationCodeServices getAuthorizationCodeServices() {
        return new InMemoryAuthorizationCodeServices();
    }

    @Bean
    public OauthAuthorizationCodeTokenGranter getOauthAuthorizationCodeTokenGranter() {
        return new OauthAuthorizationCodeTokenGranter(getAuthorizationServerTokenServices(), getAuthorizationCodeServices(), clientDetailsService(), requestFactory());
    }

    @Bean
    public OAuth2RequestFactory requestFactory() {
        OAuth2RequestFactory requestFactory = new DefaultOAuth2RequestFactory(clientDetailsService());
        return requestFactory;
    }

    @Bean
    public AuthorizationServerTokenServices getAuthorizationServerTokenServices() {
        DefaultTokenServices  defaultTokenServices = new DefaultTokenServices();
        defaultTokenServices.setTokenStore(InMemory());
        return defaultTokenServices;
    }

    @Bean
    public ClientDetailsService clientDetailsService() {
        JdbcClientDetailsService clientDetailsService = new JdbcClientDetailsService(dataSource);
        return clientDetailsService;
    }


}
